package controllers;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.ejb.EJB;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.context.FacesContext;
import javax.faces.event.ValueChangeEvent;
import javax.servlet.http.HttpSession;

import customExceptions.UserLostRightsException;

import beans.InboxBeanRemote;
import beans.RepositoryBeanRemote;
import beans.ResourcesBeanRemote;
import beans.UserBeanRemote;

import dto.AdminMessageDTO;
import dto.DTOUser;
import dto.GeneralMessageDTO;
import dto.RepositoryDTO;
import dto.ResourceDTO;

@ManagedBean
public class MessageController {

	/**
	 * @author fodorl
	 */
	private List<String> options = new ArrayList<String>();
	private List<String> resources = new ArrayList<String>();
	private List<String> usersOut = new ArrayList<String>();
	private List<String> resourcesUnlock = new ArrayList<String>();
	private List<String> usersToInvalidate = new ArrayList<String>();
	private List<String> usersRights = new ArrayList<String>();
	private String currentRes;
	private String currentOption;
	private String userName;
	private String eMail;
	private String currentUser;
	private String currentUserInv;
	private String newRepository;
	private boolean noOption = true;
	private boolean noResourceToDelete;
	private boolean noResourceToUnlock;
	private boolean noUsersToInvalidate;
	private boolean noUsersOut;
	private boolean noUsersRights;
	private String renderPopUp;
	private String currentUserRights;

	@ManagedProperty(value = "#{generalMail}")
	private GeneralMessageDTO generalMessageDTO;

	@ManagedProperty(value = "#{adminMail}")
	private AdminMessageDTO adminMessageDTO;

	@ManagedProperty(value = "#{dTOUser}")
	private DTOUser dTOUser;

	@ManagedProperty(value = "#{repositoryDTO}")
	private RepositoryDTO repositoryDTO;

	@EJB
	private InboxBeanRemote inboxBeanRemote;

	@EJB
	private ResourcesBeanRemote resourceBean;

	@EJB
	private RepositoryBeanRemote repositoryBean;

	@EJB
	private UserBeanRemote userBean;

	public void initMessageController() {
		currentUserInv = null;
		currentUserRights = null;
		currentOption = null;
		currentRes = null;
		currentUser = null;
		userName = null;
		eMail = null;
		newRepository = null;
	}

	public void initUserOptions() {
		options.add(sendMessage1("choose_option"));
		options.add(sendMessage1("delete_resource"));
		options.add(sendMessage1("unlock_resource"));
		options.add(sendMessage1("create_repository"));
	}

	public void initSupervisorOptions() {
		options.add(sendMessage1("choose_option"));
		options.add(sendMessage1("create_repository"));
		options.add(sendMessage1("delete_repository"));
		options.add(sendMessage1("transfer_rights"));
		options.add(sendMessage1("create_user"));
		options.add(sendMessage1("invalidate_user"));
		options.add(sendMessage1("user_to_repository"));
	}

	public void initUsers() {
		List<DTOUser> usersDTO = new ArrayList<DTOUser>();
		usersDTO = userBean.getUsersNotInRepository(Integer.parseInt(repositoryDTO.getRepID()));
		if (usersDTO.size() == 0) {
			noUsersOut = true;
		} else {
			usersOut.add(sendMessage1("choose_user"));
			noUsersOut = false;
			for (DTOUser userDTO : usersDTO) {
				usersOut.add(userDTO.getName());
			}
		}
	}

	public void initResources() {
		List<ResourceDTO> resourcesDTO = new ArrayList<ResourceDTO>();
		if (dTOUser.getType().equals("admin")) {
			resourcesDTO = resourceBean.getAllResources();
		} else
			resourcesDTO = resourceBean.getResourcesFromRepository(Integer.parseInt(repositoryDTO.getRepID()));
		if (resourcesDTO.size() == 0) {
			noResourceToDelete = true;
		} else {
			resources.add(sendMessage1("choose_resource"));
			noResourceToDelete = false;
			for (ResourceDTO resourceDTO : resourcesDTO) {
				resources.add(resourceDTO.getPath());
			}
		}
	}

	private void initResourcesToUnlock() {
		List<ResourceDTO> resourcesDTO = new ArrayList<ResourceDTO>();
		resourcesDTO = resourceBean.getLockedResources(Integer.parseInt(repositoryDTO.getRepID()));
		if (resourcesDTO.size() == 0) {
			noResourceToUnlock = true;
		} else {
			resourcesUnlock.add(sendMessage1("choose_resource"));
			noResourceToUnlock = false;
			for (ResourceDTO resourceDTO : resourcesDTO) {
				resourcesUnlock.add(resourceDTO.getPath());
			}
		}
	}

	public void initUsersToInvalidate() {
		List<DTOUser> usersDTO = new ArrayList<DTOUser>();
		usersDTO = userBean.getValidatedUsersFromRepository(Integer.parseInt(repositoryDTO.getRepID()));
		if (usersDTO.size() == 0) {
			noUsersToInvalidate = true;
		} else {
			usersToInvalidate.add(sendMessage1("choose_user"));
			noUsersToInvalidate = false;
			for (DTOUser userDTO : usersDTO) {
				usersToInvalidate.add(userDTO.getName());
			}
		}
	}

	public void initUsersRights() {
		List<DTOUser> usersDTO = new ArrayList<DTOUser>();
		usersDTO = userBean.getValidatedUsersFromRepository(Integer.parseInt(repositoryDTO.getRepID()));
		if (usersDTO.size() == 0) {
			noUsersRights = true;
		} else {
			usersRights.add(sendMessage1("choose_user"));
			noUsersRights = false;
			for (DTOUser userDTO : usersDTO) {
				usersRights.add(userDTO.getName());
			}
		}
	}

	public int getResourceId(String path) {
		int id = 0;
		List<ResourceDTO> resourcesDTO = new ArrayList<ResourceDTO>();
		resourcesDTO = resourceBean.getAllResources();
		for (ResourceDTO resourceDTO : resourcesDTO) {
			if (resourceDTO.getPath().equals(path)) {
				id = resourceDTO.getId();
				break;
			}
		}
		return id;
	}

	public String getUserName() {
		return userName;
	}

	public String geteMail() {
		return eMail;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public void seteMail(String eMail) {
		this.eMail = eMail;
	}

	public String getCurrentRes() {
		return currentRes;
	}

	public void setCurrentRes(String currentRes) {
		this.currentRes = currentRes;
	}

	public String getCurrentOption() {
		return currentOption;
	}

	public void setCurrentOption(String currentOption) {
		this.currentOption = currentOption;
	}

	public List<String> getResources() {
		if (this.resources.isEmpty()) {
			this.initResources();
		} return resources;
	}

	public void setResources(List<String> resources) {
		this.resources = resources;
	}

	public RepositoryDTO getRepositoryDTO() {
		return repositoryDTO;
	}

	public void setRepositoryDTO(RepositoryDTO repositoryDTO) {
		this.repositoryDTO = repositoryDTO;
	}

	public DTOUser getdTOUser() {
		return dTOUser;
	}

	public void setdTOUser(DTOUser dTOUser) {
		this.dTOUser = dTOUser;
	}

	public List<String> getUsersOut() {
		if (this.usersOut.isEmpty()) {
			this.initUsers();
		} return usersOut;
	}

	public void setUsersOut(List<String> usersOut) {
		this.usersOut = usersOut;
	}

	public List<String> getOptions() {
		if (this.options.isEmpty()) {
			if (userBean.isSupervisor(dTOUser.getId(),
					Integer.parseInt(repositoryDTO.getRepID()))) {
				this.initSupervisorOptions();
				this.initUsersToInvalidate();
				this.initUsersRights();
				this.initUsers();
			} else {
				this.initUserOptions();
				this.initResources();
				this.initResourcesToUnlock();
			}
		} return options;
	}

	public void setOptions(List<String> options) {
		this.options = options;
	}

	public String getCurrentUser() {
		return currentUser;
	}

	public void setCurrentUser(String currentUser) {
		this.currentUser = currentUser;
	}

	public List<String> getResourcesUnlock() {
		if (this.resourcesUnlock.isEmpty()) {
			this.initResourcesToUnlock();
		} return resourcesUnlock;
	}

	public void setResourcesUnlock(List<String> resourcesUnlock) {
		this.resourcesUnlock = resourcesUnlock;
	}

	public String getNewRepository() {
		return newRepository;
	}

	public void setNewRepository(String newRepository) {
		this.newRepository = newRepository;
	}

	public boolean isNoOption() {
		return noOption;
	}

	public void setNoOption(boolean noOption) {
		this.noOption = noOption;
	}

	public List<String> getUsersToInvalidate() {
		if (this.usersToInvalidate.isEmpty()) {
			this.initUsersToInvalidate();
		} return usersToInvalidate;
	}

	public boolean isNoResourceToDelete() {
		return noResourceToDelete;
	}

	public boolean isNoResourceToUnlock() {
		return noResourceToUnlock;
	}

	public boolean isNoUsersToInvalidate() {
		return noUsersToInvalidate;
	}

	public void setUsersToInvalidate(List<String> usersToInvalidate) {
		this.usersToInvalidate = usersToInvalidate;
	}

	public void setNoResourceToDelete(boolean noResourceToDelete) {
		this.noResourceToDelete = noResourceToDelete;
	}

	public void setNoResourceToUnlock(boolean noResourceToUnlock) {
		this.noResourceToUnlock = noResourceToUnlock;
	}

	public void setNoUsersToInvalidate(boolean noUsersToInvalidate) {
		this.noUsersToInvalidate = noUsersToInvalidate;
	}

	public boolean isNoUsersOut() {
		return noUsersOut;
	}

	public void setNoUsersOut(boolean noUsersOut) {
		this.noUsersOut = noUsersOut;
	}

	public String getCurrentUserInv() {
		return currentUserInv;
	}

	public void setCurrentUserInv(String currentUserInv) {
		this.currentUserInv = currentUserInv;
	}

	public boolean isNoUsersRights() {
		return noUsersRights;
	}

	public String getCurrentUserRights() {
		return currentUserRights;
	}

	public void setNoUsersRights(boolean noUsersRights) {
		this.noUsersRights = noUsersRights;
	}

	public void setCurrentUserRights(String currentUserRights) {
		this.currentUserRights = currentUserRights;
	}

	public List<String> getUsersRights() {
		if (usersRights.isEmpty()) {
			this.initUsersRights();
		} return usersRights;
	}

	public void setUsersRights(List<String> usersRights) {
		this.usersRights = usersRights;
	}
	/**
	 * @author fodorl
	 * @param e
	 */
	public void getCurrentOptionChanged(ValueChangeEvent e) {
		noOption = false;
		this.initMessageController();
		String newOption = e.getNewValue().toString();
		setCurrentOption(newOption);
	}

	public void getCurrentUserChanged(ValueChangeEvent e) {
		String newUser = e.getNewValue().toString();
		setCurrentUser(newUser);
	}

	public void getCurrentResourceChanged(ValueChangeEvent e) {
		String newResource = e.getNewValue().toString();
		setCurrentRes(newResource);
	}

	public void getCurrentUserInvChanged(ValueChangeEvent e) {
		String newUser = e.getNewValue().toString();
		setCurrentUserInv(newUser);
	}

	public void getCurrentUserRightsChanged(ValueChangeEvent e) {
		String newUser = e.getNewValue().toString();
		setCurrentUserRights(newUser);
	}
	/**
	 * @author fodorl
	 * @return xhtml face validari pe optiunile alese si adauga in baza de date
	 *         mesaje
	 */
	public String validate() {
		boolean ok = true;
		
		boolean isSupervisor = userBean.isSupervisor(dTOUser.getId(),
				Integer.parseInt(repositoryDTO.getRepID()));
		
		if ((currentOption == null)
				|| (currentOption.equals(sendMessage1("choose_option")))) {
			sendMessage("noOperationSelected");
			return null;
		}
		if (currentOption.equals(sendMessage1("delete_resource"))
				|| currentOption.equals(sendMessage1("unlock_resource"))) {

			if ((currentRes == null)
					|| (currentRes.equals(sendMessage1("choose_resource")))) {
				sendMessage("noResourceSelected");
				return null;
			} else {				
				if (currentOption.equals(sendMessage1("delete_resource"))) {
					if (getResourceId(currentRes) == 0) {
						sendMessage("resAlreadyDel");
						return null;
					} else {
						ok = addGeneralMessage(this.getResourceId(currentRes) + "", "delete_resource");
						if (!ok) {
							sendMessage("requestSent");
							return null;
						}
					}
				}
				if (currentOption.equals(sendMessage1("unlock_resource"))) {
					if (getResourceId(currentRes) == 0) {
						sendMessage("resAlreadyDel");
						return null;
					} else {
						boolean gasit = false;
						List<ResourceDTO> resourcesDTO = resourceBean
								.getLockedResources(Integer.parseInt(repositoryDTO.getRepID()));
						for (ResourceDTO resourceDTO : resourcesDTO) {
							if (resourceDTO.getPath().equals(currentRes)) {
								gasit = true;
							}
						}
						if (!gasit) {
							sendMessage("resUnlocked");
							return null;
						}
					}
					ok = addGeneralMessage(this.getResourceId(currentRes) + "" , "unlock_resource");
					if (!ok) {
						sendMessage("requestSent");
						return null;
					}
				}
			}
		}

		if (currentOption.equals(sendMessage1("create_user"))) {
			if (!isSupervisor) {
				throw new UserLostRightsException(UserLostRightsException.USER_NO_LONGER_SUPERVISOR);
			}
			
			if ((validateUserName(this.userName) == false)|| (validateeMail(this.eMail) == false)) {
				return null;
			} else {
				ok = addAdminMessage(this.userName + " " + this.eMail, "create_user");
				if (!ok) {
					sendMessage("requestSent");
					return null;
				}
			}
		}

		if (currentOption.equals(sendMessage1("invalidate_user"))) {
			if (!isSupervisor) {
				throw new UserLostRightsException(UserLostRightsException.USER_NO_LONGER_SUPERVISOR);
			}
			
			if ((currentUserInv == null)
					|| (currentUserInv.equals(sendMessage1("choose_user")))) {
				sendMessage("noUserSelected");
				return null;
			} else {
				if (!userBean.existsNameInDB(currentUserInv)) {
					sendMessage("userDel");
					return null;
				} else {
					DTOUser userB = userBean.getUserByName(currentUserInv);
					if (userB.getType().toString().equals("invalidated")) {
						sendMessage("userInvalid");
						return null;
					}
				}
				ok = addAdminMessage(userBean.getUserIdByName(currentUserInv) + "", "invalidate_user");
				if (!ok) {
					sendMessage("requestSent");
					return null;
				}
			}
		}

		if (currentOption.equals(sendMessage1("create_repository"))) {
			if (!(validateNewRepository(newRepository))) {
				return null;
			} else {
				ok = addAdminMessage(newRepository, "create_repository");
				if (!ok) {
					sendMessage("requestSent");
					return null;
				}
			}
		}

		if (currentOption.equals(sendMessage1("delete_repository"))) {
			if (!isSupervisor) {
				throw new UserLostRightsException(UserLostRightsException.USER_NO_LONGER_SUPERVISOR);
			}
			
			ok = addAdminMessage(repositoryDTO.getRepID(), "delete_repository");
			if (!ok) {
				sendMessage("requestSent");
				return null;
			}
		}

		if (currentOption.equals(sendMessage1("transfer_rights"))) {
			if (!isSupervisor) {
				throw new UserLostRightsException(UserLostRightsException.USER_NO_LONGER_SUPERVISOR);
			}
			
			if ((currentUserRights == null)
					|| (currentUserRights.equals(sendMessage1("choose_user")))) {
				sendMessage("noUserSelected");
				return null;
			}
			ok = addAdminMessage(
					repositoryDTO.getRepID() + " "
							+ userBean.getUserIdByName(currentUserRights), "transfer_rights");
			if (!ok) {
				sendMessage("requestSent");
				return null;
			}
		}

		if (currentOption.equals(sendMessage1("user_to_repository"))) {
			if (!isSupervisor) {
				throw new UserLostRightsException(UserLostRightsException.USER_NO_LONGER_SUPERVISOR);
			}
			
			if ((currentUser == null)
					|| (currentUser.equals(sendMessage1("choose_user")))) {
				sendMessage("noUserSelected");
				return null;
			} else {
				ok = addAdminMessage(Integer.parseInt(repositoryDTO.getRepID())
						+ " " + userBean.getUserIdByName(currentUser), "user_to_repository");
				if (!ok) {
					sendMessage("requestSent");
					return null;
				}
			}
		}
		// /// internationalizare
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
				.getExternalContext().getSession(true);
		LocaleController language = (LocaleController) session
				.getAttribute("language");
		String messageBundleName = "errorMessages.errors";
		if (language.getLanguage() == "ro") {
			messageBundleName += "_ro";
		} else if (language.getLanguage() == "hu") {
			messageBundleName += "_hu";
		} else if (language.getLanguage() == "de") {
			messageBundleName += "_de";
		}
		ResourceBundle messageBundle = ResourceBundle
				.getBundle(messageBundleName);
		// ///
		renderPopUp = messageBundle.getString("messageSentSucc");
		if (userBean.isSupervisor(dTOUser.getId(),
				Integer.parseInt(repositoryDTO.getRepID()))) {
			return "composeMessageSupervisor";
		} else
			return "composeMessage";
	}
	/**
	 * bakoa redirectare dupa ce apare popup
	 */
	public String redirectPopUp() {
		renderPopUp = null;
		return null;
	}
	/**
	 * @author fodorl daca username-ul introdus e corect returneaza true, altfel
	 *         returneaza false
	 * @param userN
	 * @return boolean
	 */
	public boolean validateUserName(String userN) {
		boolean ok = true;
		Pattern p = Pattern.compile("^[a-z0-9_-]{3,15}$");

		Matcher m = p.matcher(userN);

		boolean matchFound = m.matches();
		if (userN.equals("") || (userN == null)) {
			ok = false;
			sendMessage("usernameEmpty");
		} else {
			if (userN.length() < 4) {
				ok = false;
				sendMessage("usernameToShort");
			} else {
				if (userN.length() > 15) {
					ok = false;
					sendMessage("usernameTooLong");
				} else {
					if (!matchFound) {
						ok = false;
						sendMessage("usernameContainsUnapprovedCharacters");
					} else {
						if ((userBean.existsNameInDB(userN))) {
							ok = false;
							sendMessage("usernameAlreadyExists");
						}
					}
				}
			}
		}
		return ok;
	}
	/**
	 * @author fodorl daca e-mailul introdus e introdus corect returneaza true,
	 *         altfel returneaza false
	 * @param eMail
	 * @return boolean
	 */
	public boolean validateeMail(String eMail) {
		boolean ok = true;

		Pattern p = Pattern
				.compile("^[a-z0-9._%+-]+@[a-z0-9.-]+\\.[a-z]{2,4}$");

		Matcher m = p.matcher(eMail);

		boolean matchFound = m.matches();

		if (eMail.equals("") || (eMail == null)) {
			ok = false;
			sendMessage("emailEmpty");
		} else {
			if (!matchFound) {
				ok = false;
				sendMessage("emailInccorect");
			} else {
				if (eMail.length() < 8) {
					ok = false;
					sendMessage("emailTooShort");
				} else {
					if (eMail.length() > 30) {
						ok = false;
						sendMessage("emailTooLong");
					} else {
						if ((userBean.existsEmailInDB(eMail))) {
							ok = false;
							sendMessage("emailAlreadyInDatabase");
						}
					}
				}
			}
		}
		return ok;
	}
	/**
	 * @author fodorl
	 * @param repositoryName
	 * @return boolean returneaza true daca repository-ul introdus e corect,
	 *         false altfel
	 */
	public boolean validateNewRepository(String repositoryName) {
		boolean ok = true;

		Pattern p = Pattern.compile("^[a-z0-9_-]{3,15}$");

		Matcher m = p.matcher(repositoryName);

		boolean matchFound = m.matches();

		if (repositoryName.equals("") || (repositoryName == null)) {
			ok = false;
			sendMessage("repositoryNameEmpty");
		} else {
			if (repositoryName.length() < 4) {
				ok = false;
				sendMessage("repoNameisShort");
			} else {
				if (repositoryName.length() > 25) {
					ok = false;
					sendMessage("repoNameisLong");
				} else {
					if (!matchFound) {
						ok = false;
						sendMessage("repositoryNameContainsUnapprovedCharacters");
					} else {
						if (repositoryBean.existsNameInDB(newRepository)) {
							ok = false;
							sendMessage("repositoryNameIsAlreadyInDatabase");
						}
					}
				}
			}
		}
		return ok;
	}
	/**
	 * @author fodorl
	 * @return xhtml
	 */
	public String cancelU() {
		noOption = true;
		this.initMessageController();
		return "composeMessage";
	}

	public String cancelS() {
		noOption = true;
		this.initMessageController();
		return "composeMessageSupervisor";
	}
	/**
	 * @author fodorl
	 * @param content
	 * @param type
	 *            adauga un AdminMessage
	 */
	public boolean addAdminMessage(String content, String type) {

		adminMessageDTO = new AdminMessageDTO(content, dTOUser.getId(), type,
				new Date());

		if (inboxBeanRemote.addAdminMessage(adminMessageDTO)) {
			return true;
		} else
			return false;
	}
	/**
	 * @author fodorl
	 * @param content
	 * @param type
	 *            adauga un GeneralMessage
	 */
	public boolean addGeneralMessage(String content, String type) {
		generalMessageDTO = new GeneralMessageDTO(content, dTOUser.getId(),
				type, new Date(), Integer.parseInt(repositoryDTO.getRepID()));
		if (inboxBeanRemote.addGeneralMessage(generalMessageDTO)) {
			return true;
		}
		return false;
	}

	public String getRenderPopUp() {
		return renderPopUp;
	}

	public void setRenderPopUp(String renderPopUp) {
		this.renderPopUp = renderPopUp;
	}

	public void sendMessage(String text) {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
				.getExternalContext().getSession(true);
		LocaleController language = (LocaleController) session
				.getAttribute("language");
		String messageBundleName = "errorMessages.errors";
		if (language.getLanguage() == "ro") {
			messageBundleName += "_ro";
		} else if (language.getLanguage() == "hu") {
			messageBundleName += "_hu";
		} else if (language.getLanguage() == "de") {
			messageBundleName += "_de";
		}
		ResourceBundle messageBundle = ResourceBundle
				.getBundle(messageBundleName);
		FacesMessage msg = new FacesMessage(messageBundle.getString(text),
				"Error");
		msg.setSeverity(FacesMessage.SEVERITY_ERROR);
		FacesContext.getCurrentInstance().addMessage(null, msg);
	}

	public String sendMessage1(String text) {
		HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
				.getExternalContext().getSession(true);
		LocaleController language = (LocaleController) session
				.getAttribute("language");
		String messageBundleName = "errorMessages.errors";
		if (language.getLanguage() == "ro") {
			messageBundleName += "_ro";
		} else if (language.getLanguage() == "hu") {
			messageBundleName += "_hu";
		} else if (language.getLanguage() == "de") {
			messageBundleName += "_de";
		}
		ResourceBundle messageBundle = ResourceBundle
				.getBundle(messageBundleName);
		return messageBundle.getString(text);
	}
}
